/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#include "RSTControllerDesigner.h"
#include "ui_RSTControllerDesigner.h"

#include "SimInterface/ISimulator.h"

#include "AdaptDesigners/StaticAlgorithmDesigner.h"
#include "AdaptDesigners/APPAlgorithmDesigner.h"
#include "AdaptDesigners/APZP1AlgorithmDesigner.h"

#include <QMessageBox>
#include <QTimer>

#include <iostream>
#include <string>

using namespace std;
using namespace RafMat::SimInterface;

RSTControllerDesigner::RSTControllerDesigner(QWidget *parent) :
    ControllerDesigner(parent),
    ui(new Ui::RSTControllerDesigner)
{
    ui->setupUi(this);

    m_refreshTimer = new QTimer(this);
    m_refreshTimer->setInterval(1000);
    connect(m_refreshTimer, SIGNAL(timeout()), this, SLOT(on_refreshTimer_timeot()));
    m_refreshTimer->start();

    forceViewUpdate = false;

    initializeSettings();
}

void RSTControllerDesigner::initializeSettings()
{
    m_currentAdptDesigner = 0;

    ui->cbAdptType->clear();

    ui->cbAdptType->addItem("User polynomials",
                                QVariant(static_cast<int>(ISimulator::AdptTypeStatic)));

    ui->cbAdptType->addItem("Adaptive APP",
                                QVariant(static_cast<int>(ISimulator::AdptTypeAPP)));

    ui->cbAdptType->addItem("Adaptive PZP1",
                                QVariant(static_cast<int>(ISimulator::AdptTypeAPZP1)));

}

RSTControllerDesigner::~RSTControllerDesigner()
{
    delete ui;
}

void RSTControllerDesigner::on_refreshTimer_timeot()
{
    updateRSTState();
}

void RSTControllerDesigner::attachController(RafMat::SimInterface::IConfigurableSPtr ctrl)
{
    m_controllerConf = ctrl;

    try
    {
        forceViewUpdate = true;

        ISimulator::AdptType adpType = getAlgorithmType();

        // Zmień indeks w liście algorytmów.
        ui->cbAdptType->setCurrentIndex(findAlgIndex(adpType));
        changeAlgorithmDesigner(adpType);

        forceViewUpdate = false;
    }
    catch(iconf_error& e)
    {
        QMessageBox::warning(this, "Error", e.what());
        return;
    }
}

void RSTControllerDesigner::updateRSTState()
{
    try
    {
        ui->txtRPoly->setText(QString::fromStdString(m_controllerConf->getParameter("adpt::rpoly")));
        ui->txtSPoly->setText(QString::fromStdString(m_controllerConf->getParameter("adpt::spoly")));
        ui->txtTPoly->setText(QString::fromStdString(m_controllerConf->getParameter("adpt::tpoly")));
        ui->txtHValue->setText(QString::fromStdString(m_controllerConf->getParameter("adpt::h")));
    }
    catch(iconf_error& e)
    {
        QMessageBox::warning(this, "Error", e.what());
        return;
    }
}

void RSTControllerDesigner::applySettings()
{
    try
    {
        if(m_currentAdptDesigner != NULL)
            m_currentAdptDesigner->applySettings();
    }
    catch(iconf_error& e)
    {
        QMessageBox::warning(this, "Error", e.what());
    }
}

void RSTControllerDesigner::on_btnAdptSettings_clicked()
{
    if(m_currentAdptDesigner == NULL)
        return;

    m_currentAdptDesigner->show();
}

void RSTControllerDesigner::on_cbAdptType_currentIndexChanged(int index)
{
    if(!m_controllerConf)
        return;

    // Jeśli wymuszana jest zmiana indeksu listy, nic nie rób.
    if(forceViewUpdate)
        return;

    ISimulator::AdptType algType = indexToAlgType(index);

    if(algType != getAlgorithmType())
    {
        changeAlgorithmConfiguration(algType);
        changeAlgorithmDesigner(algType);
    }
}

int RSTControllerDesigner::findAlgIndex(ISimulator::AdptType adptType)
{
    return ui->cbAdptType->findData(QVariant(static_cast<int>(adptType)));
}

ISimulator::AdptType RSTControllerDesigner::indexToAlgType(int idx)
{
    return static_cast<ISimulator::AdptType>(ui->cbAdptType->itemData(idx).toInt());
}

ISimulator::AdptType RSTControllerDesigner::getAlgorithmType() const
{
    std::string stdParam = m_controllerConf->getParameter("adptindex");

    int iType = QString::fromStdString(stdParam).toInt();

    return static_cast<ISimulator::AdptType>(iType);
}

void RSTControllerDesigner::changeAlgorithmConfiguration(ISimulator::AdptType adptType)
{
    if(!m_controllerConf)
        return;

    // Nie rób nic jeśli obecna konfiguracja jest poprawna
    if(getAlgorithmType() == adptType)
        return;

    switch(adptType)
    {
    case ISimulator::AdptTypeStatic:
        m_controllerConf->setParameter("adptype", "static");
        break;

    case ISimulator::AdptTypeAPZP1:
        m_controllerConf->setParameter("adptype", "apzp1");
        break;

    case ISimulator::AdptTypeAPP:
        m_controllerConf->setParameter("adptype", "app");
        break;
    }
}

void RSTControllerDesigner::changeAlgorithmDesigner(ISimulator::AdptType adptType)
{
    if(!m_controllerConf)
        return;

    if(m_currentAdptDesigner != NULL)
    {
        delete m_currentAdptDesigner;
        m_currentAdptDesigner = NULL;
    }

    switch(adptType)
    {
    case ISimulator::AdptTypeStatic:
        m_currentAdptDesigner = new StaticAlgorithmDesigner(this);
        break;

    case ISimulator::AdptTypeAPP:
        m_currentAdptDesigner = new APPAlgorithmDesigner(this);
        break;

    case ISimulator::AdptTypeAPZP1:
        m_currentAdptDesigner = new APZP1AlgorithmDesigner(this);
        break;
    }

    m_currentAdptDesigner->attachAlgorithm(m_controllerConf);
}
